﻿using System;
using System.Collections.Generic;
using System.Configuration;
using System.Diagnostics;
using System.IO;
using System.Linq;
using System.Text;

namespace SubConvert.Core
{
    public class SubConverter
    {
        public string MkvextractPath;
        public string MkvinfoPath;
        public string Bdsup2SubPath;
        public string MkvMergePath;

        public SubConverter()
        {
            MkvextractPath = ConfigurationManager.AppSettings["MKVExtractPath"];
            MkvinfoPath = ConfigurationManager.AppSettings["MKVInfoPath"];
            Bdsup2SubPath = ConfigurationManager.AppSettings["DBSup2SubPath"];
            MkvMergePath = ConfigurationManager.AppSettings["MKVMergePath"];
        }

        public IEnumerable<Track> GetTrackInfo(string file, bool verbose)
        {
            var infoProcess = new Process
                                  {
                                      StartInfo =
                                          {
                                              FileName = MkvinfoPath,
                                              Arguments = String.Format("\"{0}\"", file),
                                              UseShellExecute = false,
                                              RedirectStandardOutput = true
                                          }
                                  };
            infoProcess.Start();
            var output = infoProcess.StandardOutput;
            var tracks = new List<Track>();
            Track currentTrack = null;
            while(output.EndOfStream == false)
            {
                var line = output.ReadLine();
                if (String.IsNullOrEmpty(line))
                {
                    continue;
                }
                if (verbose)
                {
                    Console.WriteLine(line);
                }
                if (line == "| + A track")
                {
                    if (currentTrack != null)
                    {
                        tracks.Add(currentTrack);
                    }
                    currentTrack = new Track {TrackLanguage = Constants.Languages[0]};
                    continue;
                }
                if (line.StartsWith("| +") || line.StartsWith("|+"))
                {
                    continue;
                }
                if (currentTrack == null)
                {
                    continue;
                }
                line = line.TrimStart('|', ' ', '+');
                const string trackNumber = "Track number: ";
                if (line.StartsWith(trackNumber))
                {
                    var space = line.LastIndexOf(' ');
                    var rightParen = line.LastIndexOf(')');
                    var startIndex = space + 1;
                    currentTrack.TrackNumber = line.Substring(startIndex, line.Length - (startIndex + 1));
                    //currentTrack.TrackNumber = line.Substring(trackNumber.Length, line.Length - trackNumber.Length);
                }
                const string trackType = "Track type: ";
                if (line.StartsWith(trackType))
                {
                    currentTrack.TrackType = GetTrackType(line);
                }
                else
                {
                    const string codecId = "Codec ID: ";
                    if (line.Contains(codecId))
                    {
                        currentTrack.CodecId = line.Substring(codecId.Length, line.Length - codecId.Length);
                    }
                    else
                    {
                        const string languageString = "Language: ";
                        if (line.StartsWith(languageString))
                        {
                            var languageCode = line.Substring(languageString.Length, line.Length - languageString.Length);
                            var language = Constants.Languages.FirstOrDefault(x => x.MKVCode == languageCode) ??
                                           Constants.Languages[0];
                            currentTrack.TrackLanguage = language;
                        }
                    }
                }
            }
            if (currentTrack != null)
            {
                tracks.Add(currentTrack);
            }
            infoProcess.WaitForExit();
            return tracks;
        }

        public TrackTypes GetTrackType(string line)
        {
            var trackTypes = TrackTypes.Other;
            if (line.Contains("video"))
            {
                trackTypes = TrackTypes.Video;
            }
            else if (line.Contains("audio"))
            {
                trackTypes = TrackTypes.Audio;
            }
            else if (line.Contains("subtitles"))
            {
                trackTypes = TrackTypes.Subtitles;
            }
            return trackTypes;
        }

        public bool ConvertSubtitles(string title, Track[] trackNumbers, string directory, bool verbose)
        {
            try
            {
                foreach (var track in trackNumbers)
                {
                    var extractProcess = new Process
                    {
                        StartInfo =
                        {
                            FileName = Bdsup2SubPath,
                            Arguments =
                                String.Format("\"{0}\\{1}_track{2}.sup\" \"{0}\\{1}_track{2}_exp.sub\" /lang:{3}",
                                              directory, title, track.TrackNumber, track.TrackLanguage.BDSupCode),
                            UseShellExecute = false,
                            RedirectStandardOutput = true
                        }
                    };
                    extractProcess.Start();
                    var output = extractProcess.StandardOutput;
                    while (output.EndOfStream == false)
                    {
                        var line = output.ReadLine();
                        if (line != null && line.ToLower().Contains("forced"))
                        {
                            var oldColor = Console.ForegroundColor;
                            Console.ForegroundColor = !line.ToLower().Contains(" 0 ") ? ConsoleColor.Red : ConsoleColor.Yellow;

                            SpecialWriter.WriteLine("track {0}: {1}", track.TrackNumber, line);
                            Console.ForegroundColor = oldColor;
                        }
                        if (verbose)
                        {
                            SpecialWriter.WriteLine(line);
                        }
                    }
                    extractProcess.WaitForExit();
                }
                
            }
            catch(Exception e)
            {
                Console.WriteLine(e);
                return false;
            }
            return true;
        }

        public bool ExtractSubtitles(string file, string title, IEnumerable<string> trackNumbers, string directory)
        {
            try
            {
                var args = new StringBuilder();
                args.Append(String.Format("tracks \"{0}\" ", file));
                foreach (var trackNumber in trackNumbers)
                {
                    args.Append(String.Format("{0}:\"{1}\\{2}_track{3}.sup\" ", trackNumber, directory, title, trackNumber));
                }
                var extractProcess = new Process
                {
                    StartInfo =
                    {
                        FileName = MkvextractPath,
                        RedirectStandardOutput = true
                    }
                };
                
                extractProcess.StartInfo.Arguments = args.ToString();
                extractProcess.StartInfo.UseShellExecute = false;
                extractProcess.Start();

                var output = extractProcess.StandardOutput;
                var isProgress = false;
                while (output.EndOfStream == false)
                {
                    var line = output.ReadLine();
                    isProgress = ChangeConsoleTitle(file, line, isProgress);
                    Console.WriteLine(line);
                }
                extractProcess.WaitForExit();
                Console.Title = "SubConvert";
            }
            catch (Exception e)
            {
                Console.WriteLine(e);
                return false;
            }
            return true;
        }

        private bool ChangeConsoleTitle(string title, string line, bool isProgress)
        {
            if (line.Contains("Progress: "))
            {
                if(isProgress)
                {
                    Console.CursorTop = Console.CursorTop - 1;
                }
                Console.Title = string.Format("SubConvert - {0} {1}", title, line);
                isProgress = true;
            }
            return isProgress;
        }

        public bool MergeTracks(string file, string title, IEnumerable<string> trackNumbers, string directory, string movieName,  bool keepOriginalSubs)
        {
            try
            {
                var args = new StringBuilder();
                var newName = string.Format("{0}\\{1}.mkv", directory, movieName);
                if (File.Exists(newName))
                {
                    newName = string.Format("{0}\\{1}{2}.mkv", directory, movieName, title);
                }
                newName = "\"" + newName + "\"";
                args.Append(string.Format("-o {0} --default-language eng --title \"{1}\" ", newName, movieName));
                if (!keepOriginalSubs)
                {
                    args.Append("-S ");
                }
                args.Append(string.Format("\"{0}\" ", file));
                
                foreach (var trackNumber in trackNumbers)
                {
                    args.Append(String.Format("\"{0}\\{1}_track{2}_exp.idx\" ", directory, title, trackNumber));
                }
                
                var process = new Process
                                  {
                                      StartInfo =
                                          {
                                              Arguments = args.ToString(),
                                              FileName = MkvMergePath,
                                              UseShellExecute = false,
                                              RedirectStandardOutput = true,
                                          }
                                  };
                process.Start();
                var output = process.StandardOutput;
                var isProgress = false;
                while (output.EndOfStream == false)
                {
                    var line = output.ReadLine();
                    isProgress = ChangeConsoleTitle(movieName, line, isProgress);
                    Console.WriteLine(line);
                }
                process.WaitForExit();
            }
            catch (Exception e)
            {
                Console.WriteLine(e);
                return false;
            }
            return true;
        }
    }

    

}
